/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
#include "HX711.h"
#include <stdarg.h>

char RxBuffer[RXBUFFERSIZE]; 
uint8_t usart1_RxBuffer;
uint8_t usart2_RxBuffer;
uint8_t usart3_RxBuffer;
uint8_t Uart1_Rx_Cnt = 0;
uint8_t Uart2_Rx_Cnt = 0;
uint8_t Uart3_Rx_Cnt = 0;

SEND_DATA Send_Data;
SEND_DATA usart2_Send_Data;
SEND_DATA usart3_Send_Data;
RECEIVE_DATA Receive_Data;
RECEIVE_DATA usart2_Receive_Data;
RECEIVE_DATA usart3_Receive_Data;

GPS_DATA GpsData;  // global variable

extern float filteredVoltage;
extern uint8_t enableFollowRun;
void printf_usart2(const char *fmt, ...);
/* USER CODE END 0 */

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
UART_HandleTypeDef huart3;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}
/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}
/* USART3 init function */

void MX_USART3_UART_Init(void)
{

  /* USER CODE BEGIN USART3_Init 0 */

  /* USER CODE END USART3_Init 0 */

  /* USER CODE BEGIN USART3_Init 1 */

  /* USER CODE END USART3_Init 1 */
  huart3.Instance = USART3;
  huart3.Init.BaudRate = 9600;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART3_Init 2 */

  /* USER CODE END USART3_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA1_Channel5;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);

    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA1_Channel4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* USART2 clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART2 interrupt Init */
    HAL_NVIC_SetPriority(USART2_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
  else if(uartHandle->Instance==USART3)
  {
  /* USER CODE BEGIN USART3_MspInit 0 */

  /* USER CODE END USART3_MspInit 0 */
    /* USART3 clock enable */
    __HAL_RCC_USART3_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**USART3 GPIO Configuration
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* USART3 interrupt Init */
    HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART3_IRQn);
  /* USER CODE BEGIN USART3_MspInit 1 */

  /* USER CODE END USART3_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmarx);
    HAL_DMA_DeInit(uartHandle->hdmatx);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();

    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);

    /* USART2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
  else if(uartHandle->Instance==USART3)
  {
  /* USER CODE BEGIN USART3_MspDeInit 0 */

  /* USER CODE END USART3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART3_CLK_DISABLE();

    /**USART3 GPIO Configuration
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);

    /* USART3 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART3_IRQn);
  /* USER CODE BEGIN USART3_MspDeInit 1 */

  /* USER CODE END USART3_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

#ifdef enableROS

void data_transition(void)
{

}

#endif
// Modified code in usart2_data_transition()
void usart2_data_transition(void)
{
    // usart2_Send_Data.buffer[0] = FRAME_HEADER; // Frame header
    // usart2_Send_Data.buffer[1] = GpsData.isUseful;  // GPS data identifier

    // // Copy UTC time (6 bytes) to buffer positions 2-7
    // strncpy((char *)&usart2_Send_Data.buffer[2], GpsData.UTCTime, 6);

    // // Convert latitude to 16-bit integer (scaled by 100)
    // int latitude = (int)(GpsData.latitude * 100); // 直接使用 float 值
    // usart2_Send_Data.buffer[8] = (latitude >> 8) & 0xFF;
    // usart2_Send_Data.buffer[9] = latitude & 0xFF;

    // int longitude = (int)(GpsData.longitude * 100); // 直接使用 float 值
    // usart2_Send_Data.buffer[10] = (longitude >> 8) & 0xFF;
    // usart2_Send_Data.buffer[11] = longitude & 0xFF;

    // // Direction indicators (North/South, East/West)
    // usart2_Send_Data.buffer[12] = GpsData.N_S[0]; // N/S indicator
    // usart2_Send_Data.buffer[13] = GpsData.E_W[0]; // E/W indicator

    // // Data validity flag (1 byte)
    // usart2_Send_Data.buffer[14] = GpsData.isUseful ? 0x01 : 0x00;

    // // Add filtered voltage (16-bit scaled value)
    // usart2_Send_Data.buffer[15] = ((int)filteredVoltage >> 8) & 0xFF; // High byte
    // usart2_Send_Data.buffer[16] = (int)filteredVoltage & 0xFF;        // Low byte

    // // Add weight information (16-bit scaled value)
    // usart2_Send_Data.buffer[17] = (Weight_Shiwu >> 8) & 0xFF; // High byte
    // usart2_Send_Data.buffer[18] = Weight_Shiwu & 0xFF;        // Low byte

    // // Clear remaining bytes (positions 19-21)
    // memset(&usart2_Send_Data.buffer[19], 0, 3); 

    // // Calculate checksum and append frame tail
    // usart2_Send_Data.buffer[22] = Check_Sum(22, 1); // XOR checksum of first 22 bytes
    // usart2_Send_Data.buffer[23] = FRAME_TAIL;        // Frame trailer

    // USART2_SEND(); // Trigger transmission
		
		
		/******************************************************
		字节索引	内容说明													数据类型
		-------------------------------------------------------
		0					帧头 (FRAME_HEADER)								固定标识符
		1					数据类型标识符 (GPS_DATA_ID)			固定标识符
		2-7				UTC时间（6字节字符串）						字符串
		8-9				纬度（16位整数，缩放系数100）			整数
		10-11			经度（16位整数，缩放系数100）			整数
		12				方向（N/S）												单字符
		13				方向（E/W）												单字符
		14				数据有效性标志										布尔值
		15-16			电压（16位整数，缩放系数100）			整数
		17-18			物料重量（16位整数，缩放系数100）	整数
		19-21			空闲字节（保留或清零）						保留字段
		22				校验和（XOR校验）									校验字段
		23				帧尾 (FRAME_TAIL)									固定标识符
		--------------------------------------------------------
		set encoding:GB2312(simplified)
		******************************************************/

    printf("UTC Time: %s\n", GpsData.UTCTime);                           // UTC time
    printf("Latitude: %.2f%c\n", GpsData.latitude, GpsData.N_S[0]);      // Latitude
    printf("Longitude: %.2f%c\n", GpsData.longitude, GpsData.E_W[0]);    // Longitude
    printf("Valid: %d\n", GpsData.isUseful);                             // Data validity
    printf("Voltage: %d percent\n", (int)(Voltage_Percent));               // Filtered voltage
    printf("Weight: %d g\n", Weight_Shiwu);                                // Material weight  
}

void USART1_SEND(void)
{
  unsigned char i = 0;	
	
	for(i=0; i<24; i++)
	{
		usart1_send(Send_Data.buffer[i]);
	}	 
}
void USART2_SEND(void)
{
  unsigned char i = 0;	
	
	for(i=0; i<24; i++)
	{
		usart2_send(usart2_Send_Data.buffer[i]);
	}	 
}
void USART3_SEND(void)
{
  unsigned char i = 0;	
	
	for(i=0; i<24; i++)
	{
		usart3_send(usart3_Send_Data.buffer[i]);
	}	 
}

float XYZ_Target_Speed_transition(uint8_t High,uint8_t Low)
{
	//Data conversion intermediate variable
	short transition; 
	
	//The high 8 and low 8 bits are integrated into a 16-bit short data
	transition=((High<<8)+Low); 
	return 
		transition/1000+(transition%1000)*0.001; //Unit conversion, mm/s->m/s 			
}
void usart1_send(uint8_t data)
{
    USART1->DR = data;
    while((USART1->SR&0x40)==0);  
}
void usart2_send(uint8_t data)
{
    USART2->DR = data;
    while((USART2->SR&0x40)==0);  
}
void usart3_send(uint8_t data)
{
    USART3->DR = data;
    while((USART3->SR&0x40)==0);  
}
uint8_t Check_Sum(unsigned char Count_Number,unsigned char Mode)
{
	unsigned char check_sum=0,k;
	
	if(Mode==1)
		for(k=0;k<Count_Number;k++)
		{
			check_sum=check_sum^Send_Data.buffer[k];
		}
	
	if(Mode==0)
		for(k=0;k<Count_Number;k++)
		{
			check_sum=check_sum^Receive_Data.buffer[k];
		}
	return check_sum;
}
	
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_UART_TxCpltCallback could be implemented in the user file
   */
	if(huart == &huart2)
	{
		static u8 usart2_Count=0;
		usart2_Receive_Data.buffer[usart2_Count]=usart2_RxBuffer;
		// Ensure that the first data in the array is FRAME_HEADER
		if(usart2_RxBuffer == FRAME_HEADER||usart2_Count>0) 
			usart2_Count++; 
		else 
			usart2_Count=0;
		if (usart2_Count == 11) //Verify the length of the packet
		{   
			usart2_Count=0; //Prepare for the serial port data to be refill into the array
			if(usart2_Receive_Data.buffer[10] == FRAME_TAIL) //Verify the frame tail of the packet
			{
				//Data exclusionary or bit check calculation, mode 0 is sent data check
				//if(Receive_Data.buffer[9] ==Check_Sum(9,0))	 
				{		
					//All modes flag position 0, USART3 control mode		
					if(usart2_Receive_Data.buffer[1] == 1)
					enableFollowRun = !enableFollowRun;	
					//Calculate the target speed of three axis from serial data, unit m/s
					X_Speed=-50*XYZ_Target_Speed_transition(usart2_Receive_Data.buffer[2],usart2_Receive_Data.buffer[3]);
					//Y_Speed=1000*XYZ_Target_Speed_transition(Receive_Data.buffer[4],Receive_Data.buffer[5]);
					Z_Speed=500*XYZ_Target_Speed_transition(usart2_Receive_Data.buffer[6],usart2_Receive_Data.buffer[7]);			  
				}
			}
		}
		HAL_UART_Receive_IT(&huart2, (uint8_t *)&usart2_RxBuffer, 1);
	}
	if(huart == &huart3)
	{
    static uint8_t rxIndex = 0;

    usart3_Receive_Data.buffer[rxIndex++] = usart3_RxBuffer;
    
    if (rxIndex > 2 && usart3_Receive_Data.buffer[rxIndex-2] == '\r' && usart3_Receive_Data.buffer[rxIndex-1] == '\n') 
    {
        for (int start = 0; start < rxIndex - 6; start++) 
        {
            if (usart3_Receive_Data.buffer[start] == '$' &&
                ((usart3_Receive_Data.buffer[start+3] == 'R' && usart3_Receive_Data.buffer[start+4] == 'M' && usart3_Receive_Data.buffer[start+5] == 'C') ||
                 (usart3_Receive_Data.buffer[start+2] == 'R' && usart3_Receive_Data.buffer[start+3] == 'M' && usart3_Receive_Data.buffer[start+4] == 'C'))) 
                 {
                int end;
                for (end = start; end < rxIndex; end++) 
                {
                    if (usart3_Receive_Data.buffer[end] == '\n') break;
                }
                if (end < rxIndex) 
                {
                    memset(GpsData.GPS_Buffer, 0, sizeof(GpsData.GPS_Buffer));
                    memcpy(GpsData.GPS_Buffer, &usart3_Receive_Data.buffer[start], end - start + 1);
                    GpsData.isGetData = true;
                    rxIndex = 0;
                    break;
                }
            }
        }
        
        parseGpsBuffer();
    }
    
    HAL_UART_Receive_IT(&huart3, (uint8_t *)&usart3_RxBuffer, 1);
	}
}
bool readBluetoothState(void) {
  // Read Bluetooth connection status
  bool isConnected = (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == GPIO_PIN_SET);

  return isConnected;
}

void parseGpsBuffer(void) {
  if (GpsData.isGetData) {
      char usefullFlag[2] = {0};
      char *subString = strchr(GpsData.GPS_Buffer, ',');
      if (!subString) return;

      for (int i = 0; i < 7; i++) {
          subString++;
          char *subStringNext = strchr(subString, ',');
          if (!subStringNext) break;

          switch(i) {
              case 0:
                  strncpy(GpsData.UTCTime, subString, subStringNext - subString);
                  GpsData.UTCTime[subStringNext - subString] = 0;
                  break;
              case 1:
                  strncpy(usefullFlag, subString, subStringNext - subString);
                  usefullFlag[subStringNext - subString] = 0;
                  GpsData.isUseful = (usefullFlag[0] == 'A');
                  break;
              case 2:
                  strncpy(GpsData.latitude_str, subString, subStringNext - subString);
                  GpsData.latitude_str[subStringNext - subString] = 0;
                  GpsData.latitude = atof(GpsData.latitude_str); // 转换为浮点数
                  break;
              case 3:
                  strncpy(GpsData.N_S, subString, subStringNext - subString);
                  GpsData.N_S[subStringNext - subString] = 0;
                  break;
              case 4:
                  strncpy(GpsData.longitude_str, subString, subStringNext - subString);
                  GpsData.longitude_str[subStringNext - subString] = 0;
                  GpsData.longitude = atof(GpsData.longitude_str); // 转换为浮点数
                  break;
              case 5:
                  strncpy(GpsData.E_W, subString, subStringNext - subString);
                  GpsData.E_W[subStringNext - subString] = 0;
                  break;
              case 6:
                  // 处理其他字段...
                  break;
          }
          subString = subStringNext;
      }

      GpsData.isParseData = true;
      GpsData.isGetData = false;
  }
}

//  get GPS data
void printGpsData(void) {
  printf("RAW GPS: %s\n", GpsData.GPS_Buffer);
  printf("UTC: %s | Valid: %d\n", GpsData.UTCTime, GpsData.isUseful);
  printf("Lat: %.2f %s | Lon: %.2f %s\n",
    GpsData.latitude, GpsData.N_S,
    GpsData.longitude, GpsData.E_W);
}
void printf_usart2(const char *fmt, ...) {
    char buffer[256];
    va_list args;
    
    va_start(args, fmt);          // 1. 初始化参数列表
    vsnprintf(buffer, sizeof(buffer), fmt, args); // 2. 格式化字符串到 buffer
    va_end(args);                 // 3. 清理参数列表

    // 发送 buffer 内容到 UART2
    for (int i = 0; buffer[i] != '\0'; i++) {
        HAL_UART_Transmit(&huart2, (uint8_t*)&buffer[i], 1, HAL_MAX_DELAY);
    }
}
/* USER CODE END 1 */
